﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;

namespace ComicTool
{
    public class ShortcutKeyManager
    {
        private static ShortcutKeyManager instance = new ShortcutKeyManager();
        public static ShortcutKeyManager Instance
        {
            get
            {
                return instance;
            }
        }

        private class Shortcut
        {
            public Key Key
            {
                get;
                set;
            }

            public ModifierKeys Modifiers
            {
                get;
                set;
            }

            public Action Action
            {
                get;
                set;
            }

            public virtual void Execute()
            {
                Action();
            }
        }
        private class CommandShortcut : Shortcut
        {
            public ICommand Command
            {
                get;
                set;
            }

            public override void Execute()
            {
                if (Command.CanExecute(null))
                {
                    Command.Execute(null);
                }
            }
        }

        private List<UIElement> listeners = new List<UIElement>();
        private Dictionary<ModifierKeys, HashSet<Shortcut>> modifiersToShortcuts = new Dictionary<ModifierKeys, HashSet<Shortcut>>();
        private Dictionary<Key, HashSet<Shortcut>> keysToShortcuts = new Dictionary<Key, HashSet<Shortcut>>();

        private ShortcutKeyManager()
        {
        }

        public void AddListener(UIElement element)
        {
            listeners.Add(element);
            element.KeyDown += new KeyEventHandler(element_KeyDown);
        }

        public void AddShortcut(ModifierKeys modifiers, Key key, ICommand command)
        {
            AddShortcut(new CommandShortcut()
            {
                Command = command,
                Key = key,
                Modifiers = modifiers,
            });
        }

        public void AddShortcut(ModifierKeys modifiers, Key key, Action action)
        {
            AddShortcut(new Shortcut()
             {
                 Action = action,
                 Key = key,
                 Modifiers = modifiers,
             });
        }

        private void AddShortcut(Shortcut sc)
        {
            HashSet<Shortcut> shortcuts;
            if (!modifiersToShortcuts.TryGetValue(sc.Modifiers, out shortcuts))
            {
                shortcuts = new HashSet<Shortcut>();
                modifiersToShortcuts.Add(sc.Modifiers, shortcuts);
            }
            shortcuts.Add(sc);

            shortcuts = null;
            if (!keysToShortcuts.TryGetValue(sc.Key, out shortcuts))
            {
                shortcuts = new HashSet<Shortcut>();
                keysToShortcuts.Add(sc.Key, shortcuts);
            }
            shortcuts.Add(sc);
        }

        private void element_KeyDown(object sender, KeyEventArgs e)
        {
            HashSet<Shortcut> modifierShortcuts;
            HashSet<Shortcut> keyShortcuts;
            if (modifiersToShortcuts.TryGetValue(Keyboard.Modifiers, out modifierShortcuts)
                && keysToShortcuts.TryGetValue(e.Key, out keyShortcuts))
            {
                HashSet<Shortcut> common = new HashSet<Shortcut>(keyShortcuts);
                common.IntersectWith(modifierShortcuts);
                common.ForEach(sc => sc.Execute());
            }
        }
    }
}
